/*
 * @Author: 柴靖凯 1914983264@qq.com
 * @Date: 2025-06-27 10:17:28
 * @LastEditors: 柴靖凯 1914983264@qq.com
 * @LastEditTime: 2025-06-29 08:30:54
 * @FilePath: \项目\Calculator.java
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Color;
import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
     

// ActionListener; 是java中事件处理机制的核心部分
// 为了建立计算机组件和用户操作间的回响
// 继承JFrame 为了附用Swing框架中窗口管理能力
// 为了子类可以直接调用 JFrame public的方法
public class Calculator extends JFrame implements ActionListener {

    private Image backgroundImage;

    //背景方法
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        if (backgroundImage != null) {
             g.drawImage(backgroundImage, 0, 0, getWidth(), getHeight(), this);
        }
    }

    private void showChineseTime() {
        // 获取当前日期时间
        LocalDateTime now = LocalDateTime.now();
    
        // 定义中文日期时间格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分");
    
        // 格式化日期时间为中文格式
        String chineseTime = now.format(formatter);
    
        // 显示在文本框中
        field.setText(chineseTime);
    }


    // 声明界面组件
    // 上下两个容器面板 文本框区域 按钮区域
    private JPanel north, center;

    // 文本框 显示计算过程、结果或者日期时间
    private JTextField field;

    // 按钮
    private JButton[] btns;

    // 初始化窗口-构造器 构造方法 无参构造器
    public Calculator() {
        setTitle("计算器");
        setSize(700, 700);
        // 设置窗口关闭程序
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        // 设置窗口剧中显示
        setLocationRelativeTo(null);

        // 加载背景图片
        try {
            backgroundImage = ImageIO.read(new File("background.jpg")); // 替换为你的图片路径
        } catch (IOException e) {
        System.out.println("无法加载背景图片，使用默认背景");
        }

        // 初始化界面组件
        initComponent();
        // 设置窗口显示
        setVisible(true);
    }

    private void initComponent() {
        // 1. 创建透明的内容面板（覆盖整个窗口）
        JPanel contentPane = new JPanel(new BorderLayout()) {
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                if (backgroundImage != null) {
                    // 先绘制完整背景
                    g.drawImage(backgroundImage, 0, 0, getWidth(), getHeight(), this);
                    // 再添加半透明遮罩
                    g.setColor(new Color(0, 0, 0, 150)); // 半透明黑色遮罩
                    g.fillRect(0, 0, getWidth(), getHeight());
                }
             }       
        };
        contentPane.setOpaque(false); // 设置面板透明
        setContentPane(contentPane);  // 替换窗口默认的内容面板

        // 2. 初始化顶部面板（用于放置文本框）
        north = new JPanel();
        north.setOpaque(false); // 设置面板透明
        // 3. 初始化中央面板（用于放置按钮）
        center = new JPanel();
        center.setOpaque(false); // 设置面板透明

        // 4. 初始化文本框
        field = new JTextField();
        field.setPreferredSize(new Dimension(700, 150)); // 设置文本框大小
        field.setEditable(false); // 禁止直接编辑
        field.setFont(new Font("SansSerif", Font.BOLD, 35)); // 设置字体
        field.setOpaque(false); // 设置文本框透明
        field.setForeground(Color.WHITE); // 设置文字颜色（适应深色背景）

        // 5. 定义按钮文本标签
        String[] str = new String[]{
                "7", "8", "9", "+",
                "4", "5", "6", "-",
                "1", "2", "3", "×",
                "0", ".", "=", "÷",
                "C", "B", "T", "S"
        };

        // 6. 初始化按钮数组
        btns = new JButton[str.length];
        for (int i = 0; i < btns.length; i++) {
            btns[i] = new JButton(str[i]); // 创建按钮
            btns[i].setFont(new Font("SansSerif", Font.BOLD, 25)); // 设置按钮字体
            btns[i].setOpaque(false); // 设置按钮透明
            btns[i].setContentAreaFilled(false); // 取消按钮默认填充色
            btns[i].setBorderPainted(false); // 隐藏按钮边框
            btns[i].setForeground(Color.YELLOW); // 设置按钮文字颜色为白色
        }

        // 7. 设置面板布局
        north.setLayout(new BorderLayout()); // 顶部面板使用边界布局
        center.setLayout(new GridLayout(5, 4)); // 中央面板使用5x4网格布局

        // 8. 将文本框添加到顶部面板中央
        north.add(field, BorderLayout.CENTER);

        // 9. 将所有按钮添加到中央面板
        for (JButton btn : btns) {
            center.add(btn);
        }

        // 10. 将顶部和中央面板添加到内容面板
        contentPane.add(north, BorderLayout.NORTH); // 顶部面板放在北侧
        contentPane.add(center); // 中央面板默认居中（BorderLayout.CENTER）

        // 11. 为所有按钮绑定点击事件监听器
        for (JButton btn : btns) {
            btn.addActionListener(this); // this指当前Calculator实例
        }
    }

    private void setBtnText(String text) {
        String oldText = field.getText();
        switch (text) {
            case "C":
                // 清空功能
                field.setText("");
                // System.out.println("C");
                break;
            case "B":
                // 退格
                // 1.获取输入框内容
                String numText = field.getText();
                // 俩种情况 isEmpty()另一种判断是否为空
                if (numText.length() != 0) {
                    // 输入框文本不为空
                    // 字符串长度减1（numText长度）
                    String lastText = numText.substring(0, numText.length() - 1);
                    // 将截取后的文本设置到输入框
                    field.setText(lastText);
                } else {

                }
                // System.out.println("B");
                break;
            case "T":
                // 显示中文格式的当前时间
                showChineseTime();
                break;
            case "S":
                // S 功能：计算输入数字的平方根（如果输入是一个数字）
                try {
                    //将输入框中的文本转换为 double 类型的数字
                    double num = Double.parseDouble(oldText);
                    //检查数字是否非负（平方根只能计算非负数）
                    if (num >= 0) {
                        //计算平方根
                        double result = Math.sqrt(num);
                        //将结果转换为字符串并显示在输入框中
                        field.setText(String.valueOf(result));
                    } else {
                        //处理负数情况
                        field.setText("醒不得负数算不成");
                    }
                } catch (NumberFormatException e) {
                    //处理非数字输入的异常
                    field.setText("载咋不是个数哇");
                }
                break;
            case "=":
                calculate();
                System.out.println("=");
                break;
            case ".":
                // 如果前面没有数字 那么按下小数点 自动补充为0

                // 检查输入框是否为空，或者最后一个字符是否为操作符（如 +、-、×、÷）
                if (oldText.isEmpty() || isOperator(oldText.charAt(oldText.length() - 1))) {
                    // 条件成立时（如输入框为空或刚输入完操作符），自动补0
                    // 例如：直接按小数点 → 显示 "0."
                    // 例如：输入 "5+" 后按小数点 → 显示 "5+0."
                    field.setText(oldText + "0.");
                } else if (!oldText.contains(".")) { // 避免连续出现小数点
                    // 条件不成立时，检查当前数字是否已包含小数点
                    // 若不包含小数点（如 "5"），允许添加小数点（变为 "5."）
                    // 若已包含小数点（如 "5."），拒绝重复添加（避免 "5.."）
                    field.setText(oldText + text);
                }
                break;
            default:
                // 判断当前点击的按钮是否为操作符（如 +、-、×、÷）
                // isOperator 方法通过字符比较（如 c == '+'）返回布尔值           
                if (isOperator(text.charAt(0))) {//text.charAt(0) 获取按钮文本的第一个字符
                    // 如果是操作符，需要进一步检查输入框的当前状态
                    if (!oldText.isEmpty() && !isOperator(oldText.charAt(oldText.length() - 1))) {
                        // 条件1：输入框不为空（避免操作符出现在数字前面）
                        // 条件2：输入框的最后一个字符不是操作符（避免连续操作符）
                        // 例如：当前输入框是 "3+"，再按 "-" 会被拒绝，因为最后一个字符是 "+"
                        field.setText(oldText + text);// 满足条件时，添加操作符到输入框
                    }
                } else {
                    // 如果点击的不是操作符（即数字或小数点），直接添加到输入框
                    // 数字和小数点可以连续输入（如 "3.14"）
                    field.setText(oldText + text);

                }
                break;
        }
    }

    // 判断字符是否为操作符
    private boolean isOperator(char c) {
        return c == '+' || c == '-' || c == '×' || c == '÷';
    }

    // 执行计算
    private void calculate() {
        // 如果表达式中有 ×，÷，需要替换为 *，/
        String expression = field.getText();
        //replace 是 String 类的一个方法
        //replace 将字符串中所有的（旧字符）替换为（新字符）
        expression = expression.replace("×", "*").replace("÷", "/");

        // 执行计算操作，使用计算引擎
        ScriptEngineManager manager = new ScriptEngineManager();
        // 初始化计算引擎，使用javascript解析数学表达式
        ScriptEngine engine = manager.getEngineByName("javascript");
        // 开始计算，计算过程中可能出现异常 这里需要处理异常
        try { // try 放的是可能出现异常的代码
            Object result = engine.eval(expression);
            // 结果展示到文本框
            field.setText(result.toString());
        } catch (ScriptException e) {
            // catch 中存放的是异常处理方法
            field.setText("表瞎按");
            e.printStackTrace();
        }
    }

    // 实现ActionEvent接口中的抽象方法 处理事件
    @Override
    public void actionPerformed(ActionEvent a) {
        // 此处可以捕获到ActionEvent监听事件
        // System.out.println(a.getSource());
        // 获取被点击的按钮 或按钮的文字
        Object source = a.getSource();
        if (source instanceof JButton) {
            JButton btn = (JButton) source;
            String text = btn.getText();
            // System.out.println(text);
            // 处理对因按键文字
            setBtnText(text);

        }
    }

    public static void main(String[] args) {
        // System.out.println("hhh");
        // 创建类的对象-线程不安全
        // new Calculator();

        // 是java Swing 开发中确保线程安全的核心代码
        SwingUtilities.invokeLater(Calculator::new);
    }
}